package com.bestcem.xm.txtanls.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.constant.Constants;
import com.bestcem.xm.txtanls.dao.*;
import com.bestcem.xm.txtanls.dao.mapper.HiddenKeywordMapper;
import com.bestcem.xm.txtanls.dao.mapper.JoinInfoViewpointMapper;
import com.bestcem.xm.txtanls.dao.mapper.TrainModelMapper;
import com.bestcem.xm.txtanls.dao.mapper.TxtanlsProjectMapper;
import com.bestcem.xm.txtanls.entity.SampleCopyMessage;
import com.bestcem.xm.txtanls.entity.mongo.JoinInfo;
import com.bestcem.xm.txtanls.entity.mysql.HiddenKeywordEntity;
import com.bestcem.xm.txtanls.entity.mysql.JoinInfoViewpointEntity;
import com.bestcem.xm.txtanls.entity.mysql.TrainModelDo;
import com.bestcem.xm.txtanls.entity.pojo.*;
import com.bestcem.xm.txtanls.enums.*;
import com.bestcem.xm.txtanls.grpc.client.BaseUserGrpcService;
import com.bestcem.xm.txtanls.grpc.client.TxtanlsUserGrpcService;
import com.bestcem.xm.txtanls.grpc.dto.IdMapNodeDTO;
import com.bestcem.xm.txtanls.service.KeywordService;
import com.bestcem.xm.txtanls.service.TopicService;
import com.bestcem.xm.txtanls.service.dto.train.DemoDataDTO;
import com.bestcem.xm.txtanls.service.dto.train.FreeDataDTO;
import com.bestcem.xm.txtanls.service.dto.user.OrgInfoDTO;
import com.bestcem.xm.txtanls.service.dto.user.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.common.core.constant.Constants.DEFAULT_MAP_SIZE;
import static com.bestcem.xm.txtanls.util.ViewpointUtil.FREE_DICT_VIEWS;
import static com.bestcem.xm.txtanls.util.ViewpointUtil.FREE_VIEW_DICT;

/**
 * 文本分析示例项目工具类
 *
 * @author gy.liu
 * @version v1.0
 * @date 2021/6/8 17:45
 */
@Slf4j
@Component
public class SampleUtil {
    private static List<DemoDataDTO> demoDateCache = new ArrayList<>();
    private static List<FreeDataDTO> freeDateCache = new ArrayList<>();

    @Value("${app.txtanls.copy-sample.default-org-code:catering}")
    private String oldOrgCode;

    @Resource
    private ViewpointDao viewPointDao;
    @Resource
    private AnalysisProjectDao analysisProjectDao;
    @Resource
    private KeywordService keyWordService;
    @Resource
    private IndustryToKeywordDao industryToKeywordDao;
    @Resource
    private BaseUserGrpcService baseUserGrpcService;
    @Resource
    private SampleUtil sampleUtil;
    @Resource
    private AsyncTaskUtil asyncTaskUtil;
    @Resource
    private TopicService topicService;

    @Resource
    private TxtanlsUserGrpcService txtanlsUserGrpcService;


    @Resource
    private TopicDao topicDao;

    @Resource
    private RecordDao recordDao;

    @Resource
    private JoinInfoDao joinInfoDao;

    @Resource
    private HiddenKeywordMapper hiddenKeywordMapper;

    @Resource
    private JoinInfoViewpointMapper joinInfoViewpointMapper;
    @Resource
    private TxtanlsProjectMapper txtanlsProjectMapper;

    @Resource
    private TrainModelMapper trainModelMapper;

    /**
     * 为用户创建免费项目
     *
     * @param orgId orgId
     * @author gy.liu
     * @date 2021/7/16
     */
    public void initAnalysisProjectForUse(String orgId) {

        try {
            if (log.isInfoEnabled()) {
                log.info("[Txtanls] 组织 {} 初始化文本分析示例项目", orgId);
            }

            List<UserDTO> userDTOList = baseUserGrpcService.listUserByOrgId(orgId);
            if (CollectionUtils.isEmpty(userDTOList)) {
                log.error("[Txtanls] 组织 {} 下无用户", orgId);
                return;
            }
            String userId = userDTOList.get(0).getId();
/*            AnalysisProject analysisProjectOld = analysisProjectDao.findByNameAndCreator("文本分析项目示例", "");
            if (Objects.nonNull(analysisProjectOld)) {
                log.error("[Txtanls] 组织 {} 文本分析示例项目已存在", orgId);
                return;
            }*/
            TrainModelDo byCode = trainModelMapper.getByCode(IndustryCodeEnum.DIET.getIndex());
            //初始化项目
            ProjectDO analysisProject = new ProjectDO();
            analysisProject.setName("文本分析项目示例");
            analysisProject.setCreator(userId);
            analysisProject.setStatus(AnalysisStatusEnum.FINISHED.getIndex());
            analysisProject.setOrgId(orgId);
            analysisProject.setTableId(new ObjectId().toString());
            analysisProject.setTableName("餐饮数据源demo");

            List<ProjectFieldDO> textFields = new ArrayList<>();
            ProjectFieldDO textField = new ProjectFieldDO();
            textField.setId(new ObjectId().toString());
            textField.setValue("texts");
            textFields.add(textField);
            analysisProject.setTextFieldList(textFields);

            analysisProject.setTimeFieldId(new ObjectId().toString());
            analysisProject.setTimeFieldName("times_");
            analysisProject.setTrainStatus(TrainStatusEnum.FINISHED.getIndex());
            analysisProject.setTrainProgress(Constants.PROGRESS_FINISHED);
            analysisProject.setModelId(byCode.getTrainModelId());

            ProjectDO analysisProjectNew = analysisProjectDao.insertProject(analysisProject);
            //初始化话题
            topicService.initTopic(analysisProjectNew.getId());

//            IndustryDTO industryDTO = baseUserGrpcService.getIndustryByCode(IndustryCodeEnum.DIET.getIndex());
//            String industryId = industryDTO.getId();
            // 初始化项目对应行业观点
            initView(analysisProjectNew.getId(), null);
            // 根据企业id和行业id获取行业对应行业关键词
//            List<IndustryKeywordDO> orgIndustryKeyword = industryToKeywordDao.findOrgIndustryKeyword(orgId, industryId);
//            // 未获取到行业关键词, 初始化关键词
//            if (CollectionUtils.isEmpty(orgIndustryKeyword)) {
//                keyWordService.initIndustryKeyword(orgId, industryDTO);
//            }
            //判断行业类型,返回行业相关的观点id
            List<ViewpointDO> viewpoints = viewPointDao.findAllChildrenViewPoint(analysisProjectNew.getId());
            //获取情感接口数据并且转换数据
            Map<String, Object> dataMap = getSentimentConvert();
            if (Objects.nonNull(dataMap)) {
                List<Integer> lineList = (List<Integer>) dataMap.get("lineList");
                List<String> dataTimeList = (List<String>) dataMap.get("datetime");
                List<String> textList = (List<String>) dataMap.get("text");
                List<Map<String, String>> freeDataList = (List<Map<String, String>>) dataMap.get("data");
                List<Integer> sentiTextList = (List<Integer>) dataMap.get("sentiList");
                for (int i = 0; i < freeDataList.size(); i++) {
                    Map<String, String> sentiView = freeDataList.get(i);
                    String time = dataTimeList.get(i);
                    Integer collectionId = lineList.get(i);
                    String text = textList.get(i);
                    Integer sentiValue = sentiTextList.get(i);
                    List<JoinInfo.Viewpoint> listViewPoint = new ArrayList<>();
                    // 匹配表格录入的观点和观点表里的观点
                    for (String senti : sentiView.keySet()) {
                        for (ViewpointDO child : viewpoints) {
                            // 如果观点的中文名称不同,则跳过
                            if (!child.getViewContent().equals(FREE_DICT_VIEWS.get(senti))) {
                                continue;
                            }
                            // 跳过未提及的观点
                            if (RecordSentiEnum.NONE.getIndex() == Integer.parseInt(sentiView.get(senti))) {
                                continue;
                            }
                            JoinInfo.Viewpoint viewPoint = new JoinInfo.Viewpoint();
                            viewPoint.setKey(FREE_DICT_VIEWS.get(senti));
                            viewPoint.setViewId(child.getId());
                            viewPoint.setValues(Integer.valueOf(sentiView.get(senti)));
                            viewPoint.setContent(child.getViewContent());
                            listViewPoint.add(viewPoint);
                        }
                    }

                    // 保存原话记录
                    RecordDO recordEntity = asyncTaskUtil.saveRecordNew(analysisProjectNew, time, collectionId + "", text, sentiValue, textField, null);
                    // 保存训练结果
                    asyncTaskUtil.saveJoinInfoNew(analysisProjectNew.getId(), time, collectionId + "", sentiValue, recordEntity.getId(), listViewPoint);
                }
            }
            if (log.isInfoEnabled()) {
                log.info("[Txtanls] 初始化项目信息完成: {}", analysisProjectNew.getId());
            }
        } catch (Exception e) {
            log.error("用户调用初始化项目异常:" + e);
        }
    }


    /**
     * 情感分析接口返回数据转换
     *
     * @return Map<String, Object>
     * @author gy.liu
     * @date 2021/7/19
     */
    public Map<String, Object> getSentimentConvert() {
        Map<String, Object> dataMap = new HashMap<>(DEFAULT_MAP_SIZE);
        List<Map<String, String>> freeDataList = new ArrayList<>();
        List<String> textList = new ArrayList<>();
        List<Integer> sentiList = new ArrayList<>();
        List<String> dataTimeList = new ArrayList<>();
        List<Integer> lineList = new ArrayList<>();
        //读取初始化情感结果
        List<FreeDataDTO> demoDataDTOS = sampleUtil.readFreeDataExcel();
        if (demoDataDTOS.size() > 0) {
            int i = 0;
            for (FreeDataDTO freeDataDTO : demoDataDTOS) {
                int positive = 0;
                int negative = 0;
                int neutral = 0;
                int none = 0;
                lineList.add(i);
                Field[] fields = freeDataDTO.getClass().getDeclaredFields();
                if (fields.length > 0) {
                    Map<String, String> map = new Hashtable<>();
                    for (Field field : fields) {
                        field.setAccessible(true);
                        try {
                            String value = (String) field.get(freeDataDTO);
                            String name = field.getName();
                            // 添加分析字段列表
                            if ("text".equals(name)) {
                                textList.add(value);
                            }
                            // 添加时间字段列表
                            if ("datetime".equals(name)) {
                                String recordTime = DateUtil.parse(value).toString("yyyy-MM-dd HH:mm:ss");
                                dataTimeList.add(recordTime);
                            }
                            map.put(name, value);
                            // 统计原话观点的情感
                            if (!"text".equals(name) && !"datetime".equals(name)) {
                                int valueI = Integer.parseInt(value);
                                if (RecordSentiEnum.POSITIVE.getIndex() == valueI) {
                                    positive++;
                                } else if (RecordSentiEnum.NEGATIVE.getIndex() == valueI) {
                                    negative++;
                                } else if (RecordSentiEnum.NEUTRAL.getIndex() == valueI) {
                                    neutral++;
                                } else if (RecordSentiEnum.NONE.getIndex() == valueI) {
                                    none++;
                                }
                            }
                        } catch (IllegalAccessException e) {
                            log.error("不合法数据:" + e);
                        }
                    }
                    // 根据原话的观点情感给原话情感赋值
                    if (positive > 0 && negative > 0) {
                        sentiList.add(3);
                    } else if (positive > 0 && negative == 0) {
                        sentiList.add(0);
                    } else if (positive == 0 && negative > 0) {
                        sentiList.add(1);
                    } else {
                        sentiList.add(2);
                    }
                    freeDataList.add(map);
                }
            }
            dataMap.put("text", textList);
            dataMap.put("datetime", dataTimeList);
            dataMap.put("data", freeDataList);
            dataMap.put("lineList", lineList);
            dataMap.put("sentiList", sentiList);
        }
        return dataMap;
    }

    /**
     * 初始化观点
     *
     * @param projectId
     * @param industryId
     * @return void
     * @version v1.0
     * @author gy.liu
     * @date 2021/8/3
     */
    public void initView(String projectId, String industryId) {
        List<String> views = Arrays.asList("位置", "服务", "价格", "环境", "菜品", "体验");
        for (String view : views) {
            String viewpointId = viewPointDao.insertParentViewpoint(view, projectId, industryId);
            Map<String, List<String>> viewDicts = FREE_VIEW_DICT.get(view);
            List<String> rowList = viewDicts.get("row");
            List<String> zhList = viewDicts.get("zh");
            for (int i = 0; i < rowList.size(); i++) {
                viewPointDao.insertChildrenViewpoint(zhList.get(i), rowList.get(i), projectId, viewpointId, industryId);
            }
        }
    }


    /**
     * 读训练测试表格
     *
     * @param
     * @return List<DemoDataDTO>
     * @version v1.0
     * @author gy.liu
     * @date 2021/8/3
     */
    public List<DemoDataDTO> readDemoDataExcel() {
        if (!CollectionUtils.isEmpty(demoDateCache)) {
            return demoDateCache;
        }
        ExcelReader excelReader = null;
        try {
            ClassPathResource resource = new ClassPathResource("/file/txtanls_demo.xlsx");
            DemoDataListener listener = new DemoDataListener();
            excelReader = EasyExcel.read(resource.getInputStream(), DemoDataDTO.class, listener).build();
            ReadSheet readSheet = EasyExcel.readSheet(0).build();
            excelReader.read(readSheet);
            return demoDateCache = listener.list;
        } catch (Exception e) {
            log.error("测试训练任务读表格异常:" + e);
            return null;
        } finally {
            if (excelReader != null) {
                // 这里千万别忘记关闭，读的时候会创建临时文件，到时磁盘会崩的
                excelReader.finish();
            }
        }
    }

    /**
     * 读免费项目的表格
     *
     * @param
     * @return List<DemoDataDTO>
     * @version v1.0
     * @author gy.liu
     * @date 2021/8/3
     */
    public List<FreeDataDTO> readFreeDataExcel() {
        if (!CollectionUtils.isEmpty(freeDateCache)) {
            return freeDateCache;
        }
        ExcelReader excelReader = null;
        try {
            ClassPathResource resource = new ClassPathResource("/file/free.xlsx");
            FreeDataListener listener = new FreeDataListener();
            excelReader = EasyExcel.read(resource.getInputStream(), FreeDataDTO.class, listener).build();
            ReadSheet readSheet = EasyExcel.readSheet(0).build();
            excelReader.read(readSheet);
            return freeDateCache = listener.list;
        } catch (Exception ignored) {
            log.error("文本分析初始化项目读取excel错误");
            return null;
        } finally {
            if (excelReader != null) {
                // 这里千万别忘记关闭，读的时候会创建临时文件，到时磁盘会崩的
                excelReader.finish();
            }
        }
    }

    public Object getPropertyValue(Object obj, String propertyName) throws IllegalAccessException {
        Class<?> Clazz = obj.getClass();
        Field field;
        if ((field = getField(Clazz, propertyName)) == null) {
            return null;
        }
        field.setAccessible(true);
        return field.get(obj);
    }

    public Field getField(Class<?> clazz, String propertyName) {
        if (clazz == null) {
            return null;
        }
        try {
            return clazz.getDeclaredField(propertyName);
        } catch (NoSuchFieldException e) {
            return getField(clazz.getSuperclass(), propertyName);
        }
    }

    /**
     * 文本分析copySample逻辑
     *
     * @param copyMessage 复制消息对象
     * @author liheng
     */
    public void copySample(SampleCopyMessage copyMessage) {
        String oldOrgId = "", newOrgId = "";
        if (log.isInfoEnabled()) {
            log.info("[txtanls]: copySample start，param:{}", JSONObject.toJSONString(copyMessage));
        }
        if (!Objects.isNull(copyMessage)) {
            // 文本分析不使用消息体中的就租户id
            oldOrgId = copyMessage.getOrgSrcId();
            newOrgId = copyMessage.getOrgDstId();
        }
        // 文本分析固定从一个母环境租户那里copy数据,写死orgCode catering
        OrgInfoDTO oldOrgInfo = txtanlsUserGrpcService.getOrgInfoByOrgCodeOrId(null, oldOrgId);
        if (Objects.isNull(oldOrgInfo)) {
            log.error("[Txtanls] CopySample:find old org info fail, not found! orgCode:{},oldOrgId:{} ", null, oldOrgId);
            return;
        }
//        oldOrgId = oldOrgInfo.getId();
        if (StringUtils.isEmpty(oldOrgId) || StringUtils.isEmpty(newOrgId)) {
            if (log.isInfoEnabled()) {
                log.info("[Txtanls] CopySample start {}=>{}", oldOrgId, newOrgId);
            }
            return;
        }
        // grpc获取userid 的映射map
        List<IdMapNodeDTO> idMapNodeDTOS = txtanlsUserGrpcService.getUserMapBySrcIdAndDstId(oldOrgId, newOrgId);
        if (log.isInfoEnabled()) {
            log.info("[txtanls] getUserMapBySrcIdAndDstId：param={}", JSONObject.toJSONString(idMapNodeDTOS));
        }
        Map<String, String> userIdMap = new HashMap<>();
        this.idMapCovert(idMapNodeDTOS, userIdMap);

        String industryID = oldOrgInfo.getIndustryID();
        if (StringUtils.isBlank(industryID)) {
            log.error("[txtanls] CopySample: industryId not found");
        }
        // 复制文本分析项目
        Map<String, String> newProjectId = copyProject(oldOrgId, newOrgId, userIdMap);
        if (log.isInfoEnabled()) {
            log.info("[txtanls]:CopySample 复制文本分析项目结束");
        }

        // 复制观点
        Map<String, String> viewpointIdMap = copyViewpoint(newProjectId, industryID, oldOrgId, newOrgId, userIdMap);
        if (log.isInfoEnabled()) {
            log.info("[txtanls]:CopySample 复制观点结束");
        }
        // 复制关键词
//        copyKeywords(newProjectId, industryID, oldOrgId, newOrgId, userIdMap);
//        if (log.isInfoEnabled()) {
//            log.info("[txtanls]:CopySample 复制关键词结束");
//        }
        // 复制屏蔽关键词
        copyHiddenWords(newProjectId, oldOrgId, newOrgId, userIdMap);
        if (log.isInfoEnabled()) {
            log.info("[txtanls]:CopySample 复制屏蔽关键词结束");
        }
        // 复制话题
        copyTopic(newProjectId, oldOrgId, newOrgId, userIdMap);
        if (log.isInfoEnabled()) {
            log.info("[txtanls]:CopySample 复制话题结束");
        }
        // 复制原话和情感
        copyRecord(newProjectId, industryID, viewpointIdMap, oldOrgId, newOrgId, userIdMap);
        if (log.isInfoEnabled()) {
            log.info("[txtanls]:CopySample 复制原话和原话情感结束");
        }
        if (log.isInfoEnabled()) {
            log.info("[txtanls]: copySample end");
        }
    }

    /**
     * 母环境数据copy，各个母环境从餐饮母环境复制数据
     */
    public void parentOrgCopy(String newOrgCode) {
        // 文本分析固定从一个母环境租户那里copy数据,写死orgCode catering
        OrgInfoDTO oldOrgInfo = txtanlsUserGrpcService.getOrgInfoByOrgCodeOrId(oldOrgCode, null);
        if (Objects.isNull(oldOrgInfo)) {
            log.error("[Txtanls] ParentOrgCopy:find old org info fail, not found! orgCode:{},oldOrgId:{} ", oldOrgCode, null);
            return;
        }
        OrgInfoDTO newOrgInfo = txtanlsUserGrpcService.getOrgInfoByOrgCodeOrId(newOrgCode, null);
        if (Objects.isNull(newOrgInfo)) {
            log.error("[Txtanls] ParentOrgCopy:find old org info fail, not found! orgCode:{},oldOrgId:{} ", oldOrgCode, null);
            return;
        }
        SampleCopyMessage sampleCopyMessage = new SampleCopyMessage();
        sampleCopyMessage.setOrgSrcId(oldOrgInfo.getId());
        sampleCopyMessage.setOrgDstId(newOrgInfo.getId());
        if (log.isInfoEnabled()) {
            log.info("[Txtanls] 母环境开始复制餐饮母环境数据，param:{}", JSONObject.toJSONString(sampleCopyMessage));
        }
        copySample(sampleCopyMessage);
        if (log.isInfoEnabled()) {
            log.info("[Txtanls] 母环境复制餐饮母环境数据结束，param:{}", JSONObject.toJSONString(sampleCopyMessage));
        }

    }

    public void updateProjectName(String projectName) {
        OrgInfoDTO oldOrgInfo = txtanlsUserGrpcService.getOrgInfoByOrgCodeOrId(oldOrgCode, null);
        if (Objects.isNull(oldOrgInfo)) {
            log.error("[Txtanls] updateProjectName:find old org info fail, not found! orgCode:{},oldOrgId:{} ", oldOrgCode, null);
            return;
        }
        List<ProjectDO> allProjectByOrgId = analysisProjectDao.findAllProjectByOrgId(oldOrgInfo.getId(), true);
        if (CollUtil.isEmpty(allProjectByOrgId)) {
            log.error("[Txtanls] updateProjectName:find old org info fail, not found! orgCode:{},oldOrgId:{} ", oldOrgCode, oldOrgInfo.getId());
            return;
        }
        List<String> ids = allProjectByOrgId.stream().filter(o -> "示例文本分析项目".equals(o.getName())).map(ProjectDO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(ids)) {
            log.error("[Txtanls] updateProjectName:对应组织下无示例项目 orgCode:{},oldOrgId:{} ", oldOrgCode, oldOrgInfo.getId());
            return;
        }
        log.error("[Txtanls] updateProjectName:对应组织下无示例项目 orgCode:{},oldOrgId:{},示例项目Ids:{}", oldOrgCode, oldOrgInfo.getId(), ids);
        long a = txtanlsProjectMapper.updateNameByIds(projectName, ids);
        log.error("[Txtanls] updateProjectName:修改餐饮示例项目名称成功： orgCode:{},oldOrgId:{},示例项目Ids:{},被修改项目数:{}", oldOrgCode, oldOrgInfo.getId(), ids, a);

    }

    /**
     * 复制原话和情感
     *
     * @param newProjectId
     * @param industryID
     * @param oldOrgId
     * @param newOrgId
     * @param idMapNodeDTOS
     */
    private void copyRecord(Map<String, String> newProjectId, String industryID, Map<String, String> viewpointIdMap, String oldOrgId, String newOrgId, Map<String, String> idMapNodeDTOS) {
        Map<String, String> recordIdMap = new HashMap<>(64);
        for (Map.Entry<String, String> projectEntry : newProjectId.entrySet()) {
            String oldProjectId = projectEntry.getKey();
            String newId = projectEntry.getValue();
            List<RecordDO> recordList = recordDao.listRecordByProjectId(oldProjectId);
            if (CollUtil.isNotEmpty(recordList)) {
                if (log.isInfoEnabled()) {
                    log.info("[txtanls]:文本分析原话复制,{}", JSON.toJSONString(recordList));
                }
                for (RecordDO record : recordList) {
                    String oldRecordId = record.getId();
                    String newCreateId = idMapNodeDTOS.get(record.getCreatedId());
                    record.setId(ObjectId.get().toString());
                    record.setIndustryId(industryID);
                    record.setSample(true);
                    record.setProjectId(newId);
                    record.setSurveyId(null);
                    record.setWorkTableId(null);
                    record.setWorkName("示例文本分析项目数据源");
                    record.setCollectionId(null);
                    // 使用初始化的默认字段id
                    String s = idMapNodeDTOS.get(newId);
                    record.setFieldId(s);
                    record.setFieldName("客户原话评论");
                    record.setCreatedId(newCreateId);
                    record.setUpdatedId(newCreateId);
                    RecordDO newRecord = recordDao.insertRecord(record);
                    recordIdMap.put(oldRecordId, newRecord.getId());
                }
            }

        }

        copyJoinInfo(newProjectId, viewpointIdMap, recordIdMap, idMapNodeDTOS);
    }

    /**
     * 复制观点详情信息
     *
     * @param newProjectId
     * @param viewpointIdMap
     * @param recordIdMap
     * @param idMapNodeDTOS
     */
    private void copyJoinInfo(Map<String, String> newProjectId, Map<String, String> viewpointIdMap, Map<String, String> recordIdMap, Map<String, String> idMapNodeDTOS) {
        HashMap<String, String> hashMap = new HashMap<>(128);

        for (Map.Entry<String, String> projectEntry : newProjectId.entrySet()) {
            String oldProjectId = projectEntry.getKey();
            String newId = projectEntry.getValue();
            List<JoinInfoViewpointEntity> joinInfos = joinInfoViewpointMapper.listByProjectId(oldProjectId);
            if (CollUtil.isNotEmpty(joinInfos)) {
                for (JoinInfoViewpointEntity joinInfo : joinInfos) {
                    String newCreateId = idMapNodeDTOS.get(joinInfo.getCreatorId());
                    String oldRecordId = joinInfo.getRecordId();
                    String newRecordId = recordIdMap.get(oldRecordId);
                    joinInfo.setId(ObjectId.get().toString());
                    joinInfo.setSample(true);
                    joinInfo.setProjectId(newId);
                    joinInfo.setRecordId(newRecordId);
                    joinInfo.setCreatorId(newCreateId);
                    joinInfo.setOperatorId(newCreateId);
                    hashMap.putIfAbsent(joinInfo.getMongoId(), new ObjectId().toString());
                    String mongoId = hashMap.get(joinInfo.getMongoId());
                    joinInfo.setMongoId(mongoId);
                    joinInfo.setViewId(viewpointIdMap.get(joinInfo.getViewId()));
                    if (log.isInfoEnabled()) {
                        log.info("[txtanls]:文本分析原话情感复制复制,{}", JSON.toJSONString(joinInfo));
                    }
                }
                joinInfoViewpointMapper.batchCreate(joinInfos);
            }
        }
    }

    /**
     * 复制话题
     *
     * @param newProjectId
     * @param oldOrgId
     * @param newOrgId
     * @param idMapNodeDTOS
     */
    private void copyTopic(Map<String, String> newProjectId, String oldOrgId, String newOrgId, Map<String, String> idMapNodeDTOS) {
        for (Map.Entry<String, String> projectEntry : newProjectId.entrySet()) {
            String oldProjectId = projectEntry.getKey();
            String newId = projectEntry.getValue();
            List<TopicDO> topics = topicDao.listTopicByProjectId(oldProjectId);
            if (CollUtil.isNotEmpty(topics)) {
                if (log.isInfoEnabled()) {
                    log.info("[txtanls]:文本分析话题复制,{}", JSON.toJSONString(topics));
                }

                Map<Integer, List<TopicDO>> collect = topics.stream().collect(Collectors.groupingBy(TopicDO::getType));
                List<TopicDO> topicGroups = collect.get(TopicTypeEnum.GROUP.getIndex());
                if (CollUtil.isNotEmpty(topicGroups)) {
                    for (TopicDO topicGroup : topicGroups) {
                        String oldId = topicGroup.getId();
                        String newCreateId = idMapNodeDTOS.get(topicGroup.getCreatedId());
                        topicGroup.setId(new ObjectId().toString());
                        topicGroup.setSample(true);
                        topicGroup.setProjectId(newId);
                        topicGroup.setCreatedId(newCreateId);
                        topicGroup.setUpdatedId(newCreateId);
                        TopicDO newTopicGroup = topicDao.saveTopic(topicGroup);
                        idMapNodeDTOS.put(oldId, newTopicGroup.getId());
                    }
                }
                List<TopicDO> topicChildren = collect.get(TopicTypeEnum.TOPIC.getIndex());
                if (CollUtil.isNotEmpty(topicChildren)) {
                    for (TopicDO topic : topicChildren) {
                        String oldGroupId = topic.getTopicGID();
                        String oldId = topic.getId();
                        String newCreateId = idMapNodeDTOS.get(topic.getCreatedId());
                        topic.setId(ObjectId.get().toString());
                        topic.setSample(true);
                        topic.setProjectId(newId);
                        topic.setCreatedId(newCreateId);
                        topic.setUpdatedId(newCreateId);
                        String newGroupId = idMapNodeDTOS.get(oldGroupId);
                        topic.setTopicGID(newGroupId);
                        TopicDO newTopic = topicDao.saveTopic(topic);
                        idMapNodeDTOS.put(oldId, newTopic.getId());
                    }
                }
            }
        }

    }

    /**
     * 复制屏蔽关键词
     *
     * @param newProjectId
     * @param oldOrgId
     * @param newOrgId
     * @param idMapNodeDTOS
     */
    private void copyHiddenWords(Map<String, String> newProjectId, String oldOrgId, String newOrgId, Map<String, String> idMapNodeDTOS) {
        for (Map.Entry<String, String> projectEntry : newProjectId.entrySet()) {
            String oldProjectId = projectEntry.getKey();
            String newId = projectEntry.getValue();
            List<HiddenKeywordEntity> hiddenKeywordEntities = hiddenKeywordMapper.listById(oldProjectId);
            if (CollUtil.isEmpty(hiddenKeywordEntities)) {
                continue;
            }
            if (log.isInfoEnabled()) {
                log.info("[txtanls]:文本分析屏蔽关键词复制,{}", JSON.toJSONString(hiddenKeywordEntities));
            }
            ArrayList<HiddenKeywordEntity> entities = new ArrayList<>(hiddenKeywordEntities.size());
            for (HiddenKeywordEntity hiddenKeywordEntity : hiddenKeywordEntities) {
                HiddenKeywordEntity hiddenKeyword = new HiddenKeywordEntity();
                BeanUtils.copyProperties(hiddenKeywordEntity, hiddenKeyword);
                hiddenKeyword.setHiddenKeywordId(ObjectId.get().toString());
                hiddenKeyword.setProjectId(newId);
                String newCreateId = idMapNodeDTOS.get(hiddenKeyword.getCreatorId());
                hiddenKeyword.setOperatorId(newCreateId);
                hiddenKeyword.setCreatorId(newCreateId);
                hiddenKeyword.setSample(true);
                entities.add(hiddenKeyword);
            }
            hiddenKeywordMapper.insertKeywords(entities);
        }
    }

    /**
     * 复制关键词
     *
     * @param newProjectId
     * @param industryID
     * @param oldOrgId
     * @param newOrgId
     * @param idMapNodeDTOS
     */
    private void copyKeywords(Map<String, String> newProjectId, String industryID, String oldOrgId, String newOrgId, Map<String, String> idMapNodeDTOS) {
        List<IndustryKeywordDO> orgIndustryKeyword = industryToKeywordDao.findOrgIndustryKeyword(oldOrgId, industryID);
        for (IndustryKeywordDO industryKeyword : orgIndustryKeyword) {
            industryKeyword.setId(ObjectId.get().toString());
            industryKeyword.setIndustryId(industryID);
            industryKeyword.setOrgId(newOrgId);
            industryKeyword.setIndustryId(industryID);
            String newCreateId = idMapNodeDTOS.get(industryKeyword.getCreatedId());
            industryKeyword.setCreatedId(newCreateId);
            industryKeyword.setUpdatedId(newCreateId);
            industryKeyword.setSample(true);
            if (log.isInfoEnabled()) {
                log.info("[txtanls]:文本分析行业关键词复制,{}", JSON.toJSONString(industryKeyword));
            }

            industryToKeywordDao.insertEntity(industryKeyword);
        }
    }

    /**
     * 复制观点
     *
     * @param projectIdMap
     * @param industryId
     * @param oldOrgId
     * @param newOrgId
     * @param idMapNodeDTOS
     */
    private Map<String, String> copyViewpoint(Map<String, String> projectIdMap, String industryId, String oldOrgId, String newOrgId, Map<String, String> idMapNodeDTOS) {

        if (!projectIdMap.isEmpty()) {
            for (Map.Entry<String, String> projectIdEntry : projectIdMap.entrySet()) {
                String oleProjectId = projectIdEntry.getKey();
                String newProjectId = projectIdEntry.getValue();
                if (StringUtils.isAnyEmpty(oleProjectId, newProjectId)) {
                    continue;
                }
                List<ViewpointDO> viewpoints = viewPointDao.listViewpoints(oleProjectId);
                if (CollUtil.isNotEmpty(viewpoints)) {
                    Map<Integer, List<ViewpointDO>> collect = viewpoints.stream().collect(Collectors.groupingBy(ViewpointDO::getType, Collectors.toList()));

                    List<ViewpointDO> parentViewpoints = collect.get(ViewpointTypeEnum.PARENT.getIndex());
                    for (ViewpointDO viewpoint : parentViewpoints) {
                        String oldId = viewpoint.getId();
                        viewpoint.setId(ObjectId.get().toString());
                        String newCreateId = idMapNodeDTOS.get(viewpoint.getCreateId());
                        viewpoint.setCreateId(newCreateId);
                        viewpoint.setUpdateId(newCreateId);
                        viewpoint.setProjectId(newProjectId);
                        viewpoint.setIndustryId(industryId);
                        viewpoint.setSample(true);
                        ViewpointDO newEntity = viewPointDao.insertViewpoint(viewpoint);
                        idMapNodeDTOS.put(oldId, newEntity.getId());

                    }
                    List<ViewpointDO> childViewpoints = collect.get(ViewpointTypeEnum.CHILDREN.getIndex());
                    for (ViewpointDO childViewpoint : childViewpoints) {
                        String parentViewsId = idMapNodeDTOS.get(childViewpoint.getGroupId());
                        if (StringUtils.isEmpty(parentViewsId)) {
                            continue;
                        }
                        String oldId = childViewpoint.getId();
                        childViewpoint.setId(ObjectId.get().toString());
                        String newCreateId = idMapNodeDTOS.get(childViewpoint.getCreateId());
                        childViewpoint.setCreateId(newCreateId);
                        childViewpoint.setUpdateId(newCreateId);
                        childViewpoint.setProjectId(newProjectId);
                        childViewpoint.setSample(true);
                        childViewpoint.setGroupId(parentViewsId);
                        ViewpointDO newEntity = viewPointDao.insertViewpoint(childViewpoint);
                        idMapNodeDTOS.put(oldId, newEntity.getId());

                    }

                }
            }
        }
        return idMapNodeDTOS;
    }

    /**
     * 复制文本分析项目
     *
     * @param oldOrgId      母租户id
     * @param newOrgId      新租户id
     * @param idMapNodeDTOS userId映射关系
     * @return 新文本分析项目id
     */
    private Map<String, String> copyProject(String oldOrgId, String
            newOrgId, Map<String, String> idMapNodeDTOS) {
        HashMap<String, String> projectIdMap = new HashMap<>(DEFAULT_MAP_SIZE);
        List<ProjectDO> projects = analysisProjectDao.findAllProjectByOrgId(oldOrgId, true);
        if (CollUtil.isNotEmpty(projects)) {

            for (ProjectDO project : projects) {
                String oldProjectId = project.getId();
                project.setId(null);
                project.setOrgId(newOrgId);
                project.setTableId(null);
                project.setTableName("示例文本分析项目数据源");
                project.setSample(true);
                String creator = idMapNodeDTOS.get(project.getCreator());
                project.setCreator(creator);
                project.setCreatedId(creator);
                project.setUpdatedId(creator);
                project.setSurveyId(null);
                ArrayList<ProjectFieldDO> textFieldList = new ArrayList<>();
                String fieldId = new ObjectId().toString();

                textFieldList.add(new ProjectFieldDO(fieldId, "客户原话评论", null));
                project.setTextFieldList(textFieldList);
                ProjectDO analysisProject = analysisProjectDao.insertProject(project);
                // 将新的分析项目id和对应字段id缓存使用
                idMapNodeDTOS.put(analysisProject.getId(), fieldId);
                projectIdMap.put(oldProjectId, analysisProject.getId());
            }
        }
        return projectIdMap;
    }

    /**
     * IdMapNodeDTO对象转换为map
     *
     * @param idMapNodeDTOS
     * @return Map<String, String>
     * @author liheng copy from ticket
     * @date 2021/12/07
     */
    public Map<String, String> idMapCovert
    (List<IdMapNodeDTO> idMapNodeDTOS, Map<String, String> rpcModelIdMap) {
        if (CollectionUtils.isEmpty(idMapNodeDTOS)) {
            log.error("[Ticket] 复制样类grpc调用失败");
        }

        for (IdMapNodeDTO idMapNodeDTO : idMapNodeDTOS) {
            if (StringUtils.isNotEmpty(idMapNodeDTO.getOldId()) && StringUtils.isNotEmpty(idMapNodeDTO.getNewId())) {
                rpcModelIdMap.put(idMapNodeDTO.getOldId(), idMapNodeDTO.getNewId());
            }
        }
        return rpcModelIdMap;
    }

    /**
     * 有个很重要的点 DemoDataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
     */
    static class DemoDataListener extends AnalysisEventListener<DemoDataDTO> {
        private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
        List<DemoDataDTO> list = new ArrayList<>();

        @Override
        public void invoke(DemoDataDTO map, AnalysisContext analysisContext) {
            list.add(map);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            LOGGER.info("[Txtanls] 用户初始化项目所有数据解析完成！" + list.size());
        }
    }

    /**
     * 有个很重要的点 DemoDataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
     */
    static class FreeDataListener extends AnalysisEventListener<FreeDataDTO> {
        private static final Logger LOGGER = LoggerFactory.getLogger(FreeDataListener.class);
        List<FreeDataDTO> list = new ArrayList<>();

        @Override
        public void invoke(FreeDataDTO map, AnalysisContext analysisContext) {
            list.add(map);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            LOGGER.info("[Txtanls] 用户初始化项目所有数据解析完成！" + list.size());
        }

    }
}

